#include "stdafx.h"
#include "render/rendermgr.h"
#include "game/statmgr.h"
#include "game/statmgr.h"
#include "./tankmsgobj.h"

#define BULLET_TIME_SPACE 0.5

TankMsgObj::TankMsgObj(int id, string strTankName, Point startPos, float startAngle, Color color)
: m_tankObj(id, startPos, MathUtils::AngleToRadian(startAngle), MathUtils::AngleToRadian(startAngle), color)
, m_bDestroyed(false)
, m_pReadyBullet(NULL)
, m_bShoot(false)
, m_textObj(strTankName, Point(0, 0), 10, 9, color)
, m_textPos(0, 0)
{
	CalcTextPos();
	m_textObj.SetTextPos(m_textPos);

	//init bullets
	for (int i = 0; i < MAX_BULLET_COUNT; ++i)
	{
		m_pBullets[i] = new BulletObj(id, color, &m_tankObj);
		m_pBullets[i]->SetVisible(false);
	}

	RenderMgr::GetInstance().OnBeforeRender += EventObject<OnBeforeRenderFunc>(this, &TankMsgObj::OnBeforeRender);
	m_tankObj.OnImpacted += EventObject<OnTankModelImpactedFunc>(this, &TankMsgObj::OnTankModelImpacted);
}

TankMsgObj::~TankMsgObj()
{
	m_tankObj.OnImpacted -= EventObject<OnTankModelImpactedFunc>(this, &TankMsgObj::OnTankModelImpacted);
	RenderMgr::GetInstance().OnBeforeRender -= EventObject<OnBeforeRenderFunc>(this, &TankMsgObj::OnBeforeRender);

	//init bullets
	for (int i = 0; i < MAX_BULLET_COUNT; ++i)
	{
		delete m_pBullets[i];
	}
	memset(m_pBullets, 0, sizeof(BulletObj*) * MAX_BULLET_COUNT);
	m_pReadyBullet = NULL;
}

void TankMsgObj::DoMsg(TankMsg* pMsg)
{
	m_tankObj.SetGoHeading(pMsg->bHheading);
	m_tankObj.Go(pMsg->bGo);
	m_tankObj.SetInvincible(pMsg->bInvincible);

	if (pMsg->bReverseRollAngle)
	{
		m_tankObj.ReverseRollRadian(pMsg->bRollPositive);
	}

	if (pMsg->bReverseGunAngle)
	{
		m_tankObj.ReverseGunRadian(pMsg->bGunPositive);
	}

	if (pMsg->bSetSpeed)
	{
		m_tankObj.SetSpeed(pMsg->speed);
	}

	if (pMsg->bSetRollSpeed)
	{
		m_tankObj.SetRollSpeed(pMsg->rollspeed);
	}

	if (pMsg->bSetGunSpeed)
	{
		m_tankObj.SetGunSpeed(pMsg->gunspeed);
	}

	if (pMsg->bTurnGunToAngle)
	{
		if (pMsg->dstGunRadian < -360)
		{
			pMsg->dstGunRadian = -360;
		}

		if (pMsg->dstGunRadian > 360)
		{
			pMsg->dstGunRadian = 360;
		}

		m_tankObj.TurnGunToRadian(pMsg->dstGunRadian);
	}

	if (pMsg->bTurnRollToAngle)
	{
		if (pMsg->dstRollRadian < -360)
		{
			pMsg->dstRollRadian = -360;
		}

		if (pMsg->dstRollRadian > 360)
		{
			pMsg->dstRollRadian = 360;
		}

		m_tankObj.TurnRollToRadian(pMsg->dstRollRadian);
	}

	m_bShoot = pMsg->bShoot;
}

void TankMsgObj::OnBeforeRender(float differTime)
{
	CheckBullet(differTime);

	if (m_bDestroyed)
	{
		m_tankObj.SetVisible(false);
		m_textObj.SetVisible(false);
		return;
	}

	CalcTextPos();
	m_textObj.SetTextPos(m_textPos);
}

void TankMsgObj::DestroyTank()
{
	m_tankObj.UnRegisterImpactObj();
	m_bDestroyed = true;
}

float TankMsgObj::GetRollAngle()
{
	return MathUtils::RadianToAngle(m_tankObj.GetRollRadian());
}

float TankMsgObj::GetGunAngle()
{
	return MathUtils::RadianToAngle(m_tankObj.GetGunRadian());
}

bool TankMsgObj::GetHeading()
{
	return m_tankObj.GetHeading();
}

bool TankMsgObj::GetGo()
{
	return m_tankObj.GetGo();
}

Point TankMsgObj::GetPos()
{
	return m_tankObj.GetPos();
}

float TankMsgObj::GetSpeed()
{
	return m_tankObj.GetSpeed();
}
 
float TankMsgObj::GetRollSpeed()
{
	return m_tankObj.GetRollSpeed();
}

float TankMsgObj::GetGunSpeed()
{
	return m_tankObj.GetGunSpeed();
}

void TankMsgObj::CalcTextPos()
{
	Point pos = m_tankObj.GetPos();
	float range = m_tankObj.GetRange();

	m_textPos.x = pos.x - range;
	m_textPos.y = pos.y - range - 2.5;
}

void TankMsgObj::CheckBullet(float differTime)
{
	if (m_bDestroyed)
	{
		return;
	}

	if (m_bShoot)
	{
		if (!m_pReadyBullet)
		{
			m_pReadyBullet = GetUsableBullet();
		}

		m_bShoot = false;
	}

	if (!m_pReadyBullet)
	{
		return;
	}

	time_type curTime = TimeUtils::GetTime();
	if (TimeUtils::GetTimeDiffer(curTime, m_lastBulletTime) >= BULLET_TIME_SPACE)
	{
		StatMgr::GetInstance().AddBullet(m_tankObj.GetID());

		m_pReadyBullet->SetVisible(true);	//Use
		InitBullet(m_pReadyBullet);

		m_pReadyBullet = NULL;

		m_lastBulletTime = curTime;
	}
}

void TankMsgObj::InitBullet(BulletObj* pBullet)
{
	if (!pBullet) return;

	Point pos = m_tankObj.GetPos();
	pBullet->SetBulletStart(pos, m_tankObj.GetGunRadian());
}

BulletObj* TankMsgObj::GetUsableBullet()
{
	for (int i = 0; i < MAX_BULLET_COUNT; ++i)
	{
		if (!m_pBullets[i]->GetVisible())
		{
			return m_pBullets[i];
		}
	}

	return NULL;
}

void TankMsgObj::OnTankModelImpacted()
{
	FireEvent(OnTankImpactedFunc, OnImpacted, ());
}